{
  "cells": [
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "Tce3stUlHN0L"
      },
      "source": [
        "##### Copyright 2020 The TensorFlow IO Authors."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "cellView": "form",
        "id": "tuOe1ymfHZPu"
      },
      "outputs": [],
      "source": [
        "#@title Licensed under the Apache License, Version 2.0 (the \"License\");\n",
        "# you may not use this file except in compliance with the License.\n",
        "# You may obtain a copy of the License at\n",
        "#\n",
        "# https://www.apache.org/licenses/LICENSE-2.0\n",
        "#\n",
        "# Unless required by applicable law or agreed to in writing, software\n",
        "# distributed under the License is distributed on an \"AS IS\" BASIS,\n",
        "# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n",
        "# See the License for the specific language governing permissions and\n",
        "# limitations under the License."
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "qFdPvlXBOdUN"
      },
      "source": [
        "# TensorFlow IO에서 PostgreSQL 데이터베이스 읽기"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "MfBg1C5NB3X0"
      },
      "source": [
        "<table class=\"tfo-notebook-buttons\" align=\"left\">\n",
        "  <td><a target=\"_blank\" href=\"https://www.tensorflow.org/io/tutorials/postgresql\"><img src=\"https://www.tensorflow.org/images/tf_logo_32px.png\">TensorFlow.org에서 보기</a></td>\n",
        "  <td><a target=\"_blank\" href=\"https://colab.research.google.com/github/tensorflow/docs-l10n/blob/master/site/ko/io/tutorials/postgresql.ipynb\"><img src=\"https://www.tensorflow.org/images/colab_logo_32px.png\">Google Colab에서 실행하기</a></td>\n",
        "  <td><a target=\"_blank\" href=\"https://github.com/tensorflow/docs-l10n/blob/master/site/ko/io/tutorials/postgresql.ipynb\"><img src=\"https://www.tensorflow.org/images/GitHub-Mark-32px.png\">GitHub에서소스 보기</a></td>\n",
        "      <td><a href=\"https://storage.googleapis.com/tensorflow_docs/docs-l10n/site/ko/io/tutorials/postgresql.ipynb\"><img src=\"https://www.tensorflow.org/images/download_logo_32px.png\">노트북 다운로드하기</a></td>\n",
        "</table>"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "xHxb-dlhMIzW"
      },
      "source": [
        "## 개요\n",
        "\n",
        "이 튜토리얼에서는 PostgreSQL 데이터베이스 서버에서 `tf.data.Dataset`를 생성하는 방법을 보여줍니다. 생성된 `Dataset`를 훈련이나 추론 목적으로 `tf.keras`로 전달할 수 있습니다.\n",
        "\n",
        "SQL 데이터베이스는 데이터 과학자에게 중요한 데이터 소스입니다. 가장 널리 사용되는 오픈 소스 SQL 데이터베이스 중 하나인 [PostgreSQL](https://www.postgresql.org)은 기업에서 중요 데이터와 트랜잭션 데이터를 전사적으로 저장하는 데 보편적으로 사용됩니다. PostgreSQL 데이터베이스 서버에서 직접 `Dataset`를 만들고 훈련 또는 추론 목적으로 `Dataset`를 `tf.keras`로 전달하면 데이터 파이프라인이 크게 간소화되고 데이터 과학자들이 머신러닝 모델을 빌드하는 데 집중할 수 있습니다."
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "MUXex9ctTuDB"
      },
      "source": [
        "## 설정 및 사용법"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "upgCc3gXybsA"
      },
      "source": [
        "### 필요한 tensorflow-io 패키지를 설치하고 런타임 다시 시작하기"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "uUDYyMZRfkX4"
      },
      "outputs": [],
      "source": [
        "try:\n",
        "  %tensorflow_version 2.x\n",
        "except Exception:\n",
        "  pass\n",
        "\n",
        "!pip install tensorflow-io"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "yZmI7l_GykcW"
      },
      "source": [
        "### PostgreSQL 설치 및 설정하기(선택 사항)\n",
        "\n",
        "**경고: 이 노트북은 Google Colab에서만 실행되도록 설계되었습니다**. *여기서는 시스템에 패키지를 설치하고 sudo 액세스가 필요합니다. 로컬 Jupyter 노트북에서 실행하려면 주의해서 진행해야 합니다.*\n",
        "\n",
        "Google Colab에서 사용법을 데모하기 위해 PostgreSQL 서버를 설치합니다. 암호와 빈 데이터베이스도 필요합니다.\n",
        "\n",
        "Google Colab에서 이 노트북을 실행하지 않거나 기존 데이터베이스를 사용하려는 경우 다음 설정을 건너뛰고 다음 섹션으로 진행하세요."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "YUj0878jPyz7"
      },
      "outputs": [],
      "source": [
        "# Install postgresql server\n",
        "!sudo apt-get -y -qq update\n",
        "!sudo apt-get -y -qq install postgresql\n",
        "!sudo service postgresql start\n",
        "\n",
        "# Setup a password `postgres` for username `postgres`\n",
        "!sudo -u postgres psql -U postgres -c \"ALTER USER postgres PASSWORD 'postgres';\"\n",
        "\n",
        "# Setup a database with name `tfio_demo` to be used\n",
        "!sudo -u postgres psql -U postgres -c 'DROP DATABASE IF EXISTS tfio_demo;'\n",
        "!sudo -u postgres psql -U postgres -c 'CREATE DATABASE tfio_demo;'"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "e4_59-RLMRgT"
      },
      "source": [
        "### 필요한 환경 변수 설정하기\n",
        "\n",
        "다음 환경 변수는 마지막 섹션의 PostgreSQL 설정을 기반으로 합니다. 다른 설정이 있거나 기존 데이터베이스를 사용하는 경우 적절하게 변경해야 합니다.\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "0dRotqDMswcK"
      },
      "outputs": [],
      "source": [
        "%env TFIO_DEMO_DATABASE_NAME=tfio_demo\n",
        "%env TFIO_DEMO_DATABASE_HOST=localhost\n",
        "%env TFIO_DEMO_DATABASE_PORT=5432\n",
        "%env TFIO_DEMO_DATABASE_USER=postgres\n",
        "%env TFIO_DEMO_DATABASE_PASS=postgres"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "9reCVv0mE_9O"
      },
      "source": [
        "### PostgreSQL 서버에서 데이터 준비하기\n",
        "\n",
        "이 튜토리얼에서는 데모 목적으로 데이터베이스를 생성하고 데이터베이스에 일부 데이터를 채웁니다. 이 가이드에 사용된 데이터는 [UCI 머신러닝 리포지토리](http://archive.ics.uci.edu/ml)에서 제공되는 [대기 품질 데이터세트](https://archive.ics.uci.edu/ml/datasets/Air+Quality)에서 가져온 것입니다.\n",
        "\n",
        "다음은 대기 질 데이터세트의 일부를 미리 나타낸 것입니다.\n",
        "\n",
        "날짜 | 시간 | CO (GT) | PT08.S1 (CO) | NMHC (GT) | C6H6 (GT) | PT08.S2 (NMHC) | NOx (GT) | PT08.S3 (NOx) | NO2 (GT) | PT08.S4 (NO2) | PT08.S5 (O3) | 티 | RH | AH\n",
        "--- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | ---\n",
        "10/03/2004 | 18.00.00 | 2,6 | 1360 | 150 | 11,9 | 1046 | 166 | 1056 | 113 | 1692 년 | 1268 년 | 13,6 | 48,9 | 0,7578\n",
        "10/03/2004 | 19.00.00 | 2 | 1292 | 112 | 9,4 | 955 | 103 | 1174 년 | 92 | 1559 년 | 972 | 13,3 | 47,7 | 0,7255\n",
        "10/03/2004 | 20.00.00 | 2,2 | 1402 | 88 | 9,0 | 939 | 131 | 1140 년 | 114 | 1555 년 | 1074 | 11,9 | 54,0 | 0,7502\n",
        "10/03/2004 | 21.00.00 | 2,2 | 1376 | 80 | 9,2 | 948 | 172 | 1092 | 122 | 1584 년 | 1203 년 | 11,0 | 60,0 | 0,7867\n",
        "10/03/2004 | 22.00.00 | 1,6 | 1272 | 51 | 6,5 | 836 | 131 | 1205 년 | 116 | 1490 | 1110 년 | 11,2 | 59,6 | 0,7888\n",
        "\n",
        "대기 품질 데이터세트 및 UCI 머신러닝 리포지토리에 대한 자세한 정보는 [참고 문헌](#references) 섹션에서 확인할 수 있습니다.\n",
        "\n",
        "데이터 준비를 단순화하기 위해 대기 품질 데이터세트의 SQL 버전이 준비되었으며 [AirQualityUCI.sql](https://github.com/tensorflow/io/blob/master/docs/tutorials/postgresql/AirQualityUCI.sql)로 제공됩니다.\n",
        "\n",
        "테이블을 만드는 문은 다음과 같습니다.\n",
        "\n",
        "```\n",
        "CREATE TABLE AirQualityUCI (   Date DATE,   Time TIME,   CO REAL,   PT08S1 INT,   NMHC REAL,   C6H6 REAL,   PT08S2 INT,   NOx REAL,   PT08S3 INT,   NO2 REAL,   PT08S4 INT,   PT08S5 INT,   T REAL,   RH REAL,   AH REAL );\n",
        "```\n",
        "\n",
        "데이터베이스에 테이블을 만들고 데이터를 채우는 전체 명령은 다음과 같습니다."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "W1eVidg3JrPV"
      },
      "outputs": [],
      "source": [
        "!curl -s -OL https://github.com/tensorflow/io/raw/master/docs/tutorials/postgresql/AirQualityUCI.sql\n",
        "\n",
        "!PGPASSWORD=$TFIO_DEMO_DATABASE_PASS psql -q -h $TFIO_DEMO_DATABASE_HOST -p $TFIO_DEMO_DATABASE_PORT -U $TFIO_DEMO_DATABASE_USER -d $TFIO_DEMO_DATABASE_NAME -f AirQualityUCI.sql"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "acEST3amdyDI"
      },
      "source": [
        "### PostgreSQL 서버에서 데이터세트를 만들고 TensorFlow에서 사용하기\n",
        "\n",
        "PostgreSQL 서버에서 데이터세트를 만들려면 `query` 및 `endpoint` 인수를 사용하여 `tfio.experimental.IODataset.from_sql`을 호출하기만 하면 됩니다. `query`는 테이블의 선택 열에 대한 SQL 쿼리이고 `endpoint` 인수는 주소 및 데이터베이스 이름입니다."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "h21RdP7meGzP"
      },
      "outputs": [],
      "source": [
        "import os\n",
        "import tensorflow_io as tfio\n",
        "\n",
        "endpoint=\"postgresql://{}:{}@{}?port={}&dbname={}\".format(\n",
        "    os.environ['TFIO_DEMO_DATABASE_USER'],\n",
        "    os.environ['TFIO_DEMO_DATABASE_PASS'],\n",
        "    os.environ['TFIO_DEMO_DATABASE_HOST'],\n",
        "    os.environ['TFIO_DEMO_DATABASE_PORT'],\n",
        "    os.environ['TFIO_DEMO_DATABASE_NAME'],\n",
        ")\n",
        "\n",
        "dataset = tfio.experimental.IODataset.from_sql(\n",
        "    query=\"SELECT co, pt08s1 FROM AirQualityUCI;\",\n",
        "    endpoint=endpoint)\n",
        "\n",
        "print(dataset.element_spec)"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "8y-VpwcWNYTF"
      },
      "source": [
        "위의 `dataset.element_spec` 출력에서 볼 수 있듯이 생성된 `Dataset`의 요소는 데이터베이스 테이블의 열 이름을 키로 사용하는 Python dict 객체입니다.\n",
        "\n",
        "```\n",
        "{   'co': TensorSpec(shape=(), dtype=tf.float32, name=None),   'pt08s1': TensorSpec(shape=(), dtype=tf.int32, name=None), }\n",
        "```\n",
        "\n",
        "추가 연산을 적용하기가 매우 편리합니다. 예를 들어 `Dataset`의 `nox` 및 `no2` 필드를 모두 선택하고 차이를 계산할 수 있습니다."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "qCoueXYZOvqZ"
      },
      "outputs": [],
      "source": [
        "dataset = tfio.experimental.IODataset.from_sql(\n",
        "    query=\"SELECT nox, no2 FROM AirQualityUCI;\",\n",
        "    endpoint=endpoint)\n",
        "\n",
        "dataset = dataset.map(lambda e: (e['nox'] - e['no2']))\n",
        "\n",
        "# check only the first 20 record\n",
        "dataset = dataset.take(20)\n",
        "\n",
        "print(\"NOx - NO2:\")\n",
        "for difference in dataset:\n",
        "  print(difference.numpy())"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "xO2pheWEPQSU"
      },
      "source": [
        "생성된 `Dataset`는 이제 훈련 또는 추론 목적으로 `tf.keras`로 직접 전달할 수 있습니다."
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "AzQoxSlHVv1k"
      },
      "source": [
        "## 참고 문헌\n",
        "\n",
        "- Dua, D. and Graff, C. (2019). UCI Machine Learning Repository [http://archive.ics.uci.edu/ml]. Irvine, CA: University of California, School of Information and Computer Science.\n",
        "- S. De Vito, E. Massera, M. Piga, L. Martinotto, G. Di Francia, On field calibration of an electronic nose for benzene estimation in an urban pollution monitoring scenario, Sensors and Actuators B: Chemical, Volume 129, Issue 2, 22 February 2008, Pages 750-757, ISSN 0925-4005"
      ]
    }
  ],
  "metadata": {
    "colab": {
      "collapsed_sections": [
        "Tce3stUlHN0L"
      ],
      "name": "postgresql.ipynb",
      "toc_visible": true
    },
    "kernelspec": {
      "display_name": "Python 3",
      "name": "python3"
    }
  },
  "nbformat": 4,
  "nbformat_minor": 0
}
